import os
import sys
import shutil
import time
import uuid
from cover_image import add_book_name_to_image
import xml.etree.ElementTree as ET
from xml.dom import minidom
from PIL import Image
from fontTools.ttLib import TTFont
from fontTools.subset import Subsetter, Options


def get_template_dir():
    """获取模板目录路径，兼容打包和开发环境"""
    if getattr(sys, 'frozen', False):
        # 打包后，模板在临时解压目录（`sys._MEIPASS`）
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(sys.executable))
        return os.path.join(base_path, 'template')
    else:
        # 开发环境，模板在脚本目录
        return os.path.join(os.path.dirname(os.path.dirname(__file__)), 'template')


def copy_template(novel_name, txt_file_path):
    """复制模板文件夹到新目录
    Args:
        novel_name: 小说名称，用作新目录名
        txt_file_path: txt文件路径，用于确定目标目录
    Returns:
        str: 创建的目标目录路径
    """
    template_dir = get_template_dir()
    target_dir = os.path.join(os.path.dirname(txt_file_path), novel_name)
    try:
        # 确保模板目录存在
        if not os.path.exists(template_dir):
            print(f"错误：模板目录不存在：{template_dir}")
            raise FileNotFoundError(f"模板目录不存在：{template_dir}")

        if os.path.exists(target_dir):
            shutil.rmtree(target_dir)
        shutil.copytree(template_dir, target_dir)
        print(f"已复制模板文件到：{target_dir}")
        return target_dir
    except Exception as e:
        print(f"错误：复制模板时出现问题：{str(e)}")
        # 改为抛出异常而不是退出
        raise


def clear_text_directory(text_dir):
    """清空OEBPS/Text目录下的所有文件
    Args:
        text_dir: OEBPS/Text目录的路径
    """
    if os.path.exists(text_dir):
        for file in os.listdir(text_dir):
            file_path = os.path.join(text_dir, file)
            if os.path.isfile(file_path):
                os.remove(file_path)


def copy_xhtml_files(src_dir, text_dir):
    """将XHTML文件复制到OEBPS/Text目录
    Args:
        src_dir: 源文件夹
        text_dir: 目标Text目录路径
    """
    xhtml_dir = os.path.join(os.path.dirname(
        src_dir), f'{os.path.basename(src_dir)}_xhtml')
    if os.path.exists(xhtml_dir):
        copied = False
        for file in os.listdir(xhtml_dir):
            if file.endswith('.xhtml'):
                src_file = os.path.join(xhtml_dir, file)
                dst_file = os.path.join(text_dir, file)
                try:
                    shutil.copy2(src_file, dst_file)
                    copied = True
                except Exception as e:
                    print(f"错误：复制文件 {file} 时出错：{str(e)}")
                    raise
        if copied:
            print(f"已复制章节文件到：{text_dir}")
        else:
            raise FileNotFoundError("没有找到任何XHTML文件可以复制")
    else:
        raise FileNotFoundError(f"未找到XHTML源文件夹: {xhtml_dir}")


def copy_fixed_files(text_dir):
    """从模板目录复制固定的xhtml文件到目标目录
    Args:
        text_dir: 目标Text目录路径
    """
    # 修改模板目录的获取方式
    template_dir = get_template_dir()
    template_text_dir = os.path.join(template_dir, 'OEBPS', 'Text')

    fixed_files = ['copyright.xhtml', 'cover.xhtml', 'desc.xhtml']
    for file in fixed_files:
        src_file = os.path.join(template_text_dir, file)
        dst_file = os.path.join(text_dir, file)
        if os.path.exists(src_file):
            shutil.copy2(src_file, dst_file)
    print(f"已复制版权、简介文件到: {text_dir}")


def update_content_opf(target_dir, text_dir, novel_name):
    """使用XML格式更新content.opf文件
    Args:
        target_dir: 目标目录路径
        text_dir: OEBPS/Text目录路径
        novel_name: 小说名称
    """
    toc_path = os.path.join(target_dir, 'OEBPS', 'content.opf')
    if os.path.exists(toc_path):
        # 注册命名空间
        ET.register_namespace('', 'http://www.idpf.org/2007/opf')
        ET.register_namespace('dc', 'http://purl.org/dc/elements/1.1/')

        # 解析XML文件
        tree = ET.parse(toc_path)
        root = tree.getroot()

        # 更新标题
        title = root.find('.//{http://purl.org/dc/elements/1.1/}title')
        if title is not None:
            title.text = novel_name

        # 更新manifest
        manifest = root.find('.//{http://www.idpf.org/2007/opf}manifest')
        if manifest is not None:
            # 找到desc.xhtml的位置
            desc_item = manifest.find(".//*[@id='desc.xhtml']")
            if desc_item is not None:
                # 获取所有xhtml文件并排序
                xhtml_files = sorted(
                    [f for f in os.listdir(text_dir) if f.endswith('.xhtml')])

                # 在desc.xhtml后面插入所有xhtml文件
                desc_index = list(manifest).index(desc_item)
                for xhtml_file in xhtml_files:
                    item = ET.Element('{http://www.idpf.org/2007/opf}item')
                    item.set('id', xhtml_file)
                    item.set('href', f'Text/{xhtml_file}')
                    item.set('media-type', 'application/xhtml+xml')
                    manifest.insert(desc_index + 1, item)
                    desc_index += 1

        # 更新spine
        spine = root.find('.//{http://www.idpf.org/2007/opf}spine')
        if spine is not None:
            # 找到desc.xhtml的位置
            desc_ref = spine.find(".//*[@idref='desc.xhtml']")
            if desc_ref is not None:
                # 获取所有xhtml文件并排序
                xhtml_files = sorted(
                    [f for f in os.listdir(text_dir) if f.endswith('.xhtml')])

                # 在desc.xhtml后面插入所有xhtml文件
                desc_index = list(spine).index(desc_ref)
                for xhtml_file in xhtml_files:
                    itemref = ET.Element(
                        '{http://www.idpf.org/2007/opf}itemref')
                    itemref.set('idref', xhtml_file)
                    spine.insert(desc_index + 1, itemref)
                    desc_index += 1

        # 保存修改后的文件
        xml_str = ET.tostring(root, encoding='utf-8')
        reparsed = minidom.parseString(xml_str)
        formatted_xml = reparsed.toprettyxml(indent="  ")

        # 移除多余的空行
        lines = formatted_xml.splitlines()
        filtered_lines = [line for line in lines if line.strip()]
        formatted_content = '\n'.join(filtered_lines)

        with open(toc_path, 'w', encoding='utf-8') as f:
            f.write(formatted_content)
        print(f"已更新文件：{toc_path}")
    else:
        print(f"错误：未找到文件 {toc_path}")
        sys.exit(1)


def update_toc_ncx(target_dir, novel_name, toc_data):
    """更新toc.ncx文件
    Args:
        target_dir: 目标目录路径
        novel_name: 小说名
        toc_data: 目录数据，包含卷和章节信息的列表
    """
    toc_path = os.path.join(target_dir, 'OEBPS', 'toc.ncx')
    if os.path.exists(toc_path):
        # 注册命名空间
        ET.register_namespace('', 'http://www.daisy.org/z3986/2005/ncx/')

        # 解析XML文件
        tree = ET.parse(toc_path)
        root = tree.getroot()

        # 更新UUID
        meta_uid = root.find('.//{http://www.daisy.org/z3986/2005/ncx/}meta[@name="dtb:uid"]')
        if meta_uid is not None:
            meta_uid.set('content', f'urn:uuid:{str(uuid.uuid4())}')

        # 定义命名空间
        ns = {'ncx': 'http://www.daisy.org/z3986/2005/ncx/'}

        # 更新docTitle
        doc_title = root.find('.//ncx:docTitle/ncx:text', ns)
        if doc_title is not None:
            doc_title.text = novel_name

        # 查找navMap元素
        nav_map = root.find('.//ncx:navMap', ns)
        if nav_map is not None:
            # 清空现有的navPoint
            for child in list(nav_map):
                nav_map.remove(child)

            # 添加固定的导航点
            fixed_navpoints = [
                {"id": "1", "text": "书籍封面", "src": "Text/cover.xhtml"},
                {"id": "2", "text": "版权信息", "src": "Text/copyright.xhtml"},
                {"id": "3", "text": "书籍简介", "src": "Text/desc.xhtml"}
            ]

            play_order = 1
            for nav in fixed_navpoints:
                nav_point = ET.SubElement(nav_map, '{http://www.daisy.org/z3986/2005/ncx/}navPoint',
                                          {'id': f'navPoint-{nav["id"]}', 'playOrder': str(play_order)})
                nav_label = ET.SubElement(
                    nav_point, '{http://www.daisy.org/z3986/2005/ncx/}navLabel')
                text = ET.SubElement(
                    nav_label, '{http://www.daisy.org/z3986/2005/ncx/}text')
                text.text = nav["text"]
                ET.SubElement(nav_point, '{http://www.daisy.org/z3986/2005/ncx/}content',
                              {'src': nav["src"]})
                play_order += 1

            # 添加新的目录结构
            for item in toc_data:
                if item['type'] == 'volume':
                    # 创建卷的navPoint
                    volume_point = ET.SubElement(nav_map, '{http://www.daisy.org/z3986/2005/ncx/}navPoint',
                                                 {'id': f'navPoint-{play_order}', 'playOrder': str(play_order)})

                    # 添加卷标题
                    nav_label = ET.SubElement(
                        volume_point, '{http://www.daisy.org/z3986/2005/ncx/}navLabel')
                    text = ET.SubElement(
                        nav_label, '{http://www.daisy.org/z3986/2005/ncx/}text')
                    text.text = item['title']

                    # 添加卷内容链接
                    ET.SubElement(volume_point, '{http://www.daisy.org/z3986/2005/ncx/}content',
                                  {'src': f'Text/{item["file"]}'})

                    play_order += 1

                    # 添加卷下的章节
                    for chapter in item['chapters']:
                        chapter_point = ET.SubElement(volume_point, '{http://www.daisy.org/z3986/2005/ncx/}navPoint',
                                                      {'id': f'navPoint-{play_order}', 'playOrder': str(play_order)})

                        # 添加章节标题
                        chapter_label = ET.SubElement(
                            chapter_point, '{http://www.daisy.org/z3986/2005/ncx/}navLabel')
                        chapter_text = ET.SubElement(
                            chapter_label, '{http://www.daisy.org/z3986/2005/ncx/}text')
                        chapter_text.text = format_chapter_title(chapter['title'])

                        # 添加章节内容链接
                        ET.SubElement(chapter_point, '{http://www.daisy.org/z3986/2005/ncx/}content',
                                      {'src': f'Text/{chapter["file"]}'})

                        play_order += 1
                else:
                    # 直接添加章节
                    chapter_point = ET.SubElement(nav_map, '{http://www.daisy.org/z3986/2005/ncx/}navPoint',
                                                  {'id': f'navPoint-{play_order}', 'playOrder': str(play_order)})

                    # 添加章节标题
                    chapter_label = ET.SubElement(
                        chapter_point, '{http://www.daisy.org/z3986/2005/ncx/}navLabel')
                    chapter_text = ET.SubElement(
                        chapter_label, '{http://www.daisy.org/z3986/2005/ncx/}text')
                    chapter_text.text = format_chapter_title(item['title'])

                    # 添加章节内容链接
                    ET.SubElement(chapter_point, '{http://www.daisy.org/z3986/2005/ncx/}content',
                                                 {'src': f'Text/{item["file"]}'})

                    play_order += 1

        # 保存修改后的文件，添加格式化并移除多余空行
        from xml.dom import minidom
        xml_str = ET.tostring(root, encoding='utf-8')
        reparsed = minidom.parseString(xml_str)
        # 获取格式化的XML字符串
        formatted_xml = reparsed.toprettyxml(indent="  ", encoding='utf-8')

        # 移除多余的空行
        lines = formatted_xml.decode('utf-8').splitlines()
        filtered_lines = [line for line in lines if line.strip()]

        # 添加DOCTYPE声明
        doctype = '<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">'
        filtered_lines.insert(1, doctype)

        formatted_content = '\n'.join(filtered_lines)

        # 写入文件
        with open(toc_path, 'w', encoding='utf-8') as f:
            f.write(formatted_content)
        print(f"已更新文件：{toc_path}")
    else:
        print(f"错误：未找到文件 {toc_path}")
        sys.exit(1)

def format_chapter_title(title):
        """将章节标题统一格式化为"第X章"样式"""
        # 处理数字序号格式 (比如 "001：" 或 "1：")
        if ':' in title or '：' in title:
            number = title.split('：')[0].split(':')[0].strip()
            try:
                chapter_num = int(number)
                rest_title = title.split('：')[-1].split(':')[-1].strip()
                return f"第{chapter_num}章 {rest_title}"
            except ValueError:
                return title
        return title

def process_cover_image(bookName, source_image_path, target_dir):
    """处理封面图片，调整尺寸和分辨率
    Args:
        bookName: 书名
        source_image_path: 源图片路径
        target_dir: 目标目录路径
    """
    try:
        # 获取模板封面图片路径
        template_dir = get_template_dir()
        template_cover_path = os.path.join(template_dir, 'OEBPS', 'Images', 'cover.jpg')

        # 检查源图片是否与模板图片一致
        if os.path.exists(template_cover_path):
            with open(source_image_path, 'rb') as src_file, open(template_cover_path, 'rb') as tmp_file:
                if src_file.read() == tmp_file.read():
                    print("检测到使用默认封面，开始重新绘制...")
                    source_image_path = os.path.join(target_dir, 'OEBPS', 'Images', 'coverTxt.jpg')
                    add_book_name_to_image(bookName, source_image_path)
        # 构建目标文件路径
        target_path = os.path.join(target_dir, 'OEBPS', 'Images', 'cover.jpg')
        # 打开原始图片
        with Image.open(source_image_path) as img:
            # 调整图片尺寸
            resized_img = img.resize((1080, 1440), Image.Resampling.LANCZOS)
            # 设置DPI
            resized_img.info['dpi'] = (150, 150)

            # 保存处理后的图片
            resized_img.save(target_path, 'JPEG', quality=95, dpi=(150, 150))
            return True
    except Exception as e:
        print(f"处理封面图片时出错：{str(e)}")

def process_back_image(source_image_path, target_dir):
    """处理背景图片，调整尺寸和分辨率
    Args:
        source_image_path: 源图片路径
        target_dir: 目标目录路径
    """
    try:
        # 打开原始图片
        with Image.open(source_image_path) as img:
            # 调整图片尺寸
            resized_img = img.resize((1080, 1920), Image.Resampling.LANCZOS)

            # 设置DPI
            resized_img.info['dpi'] = (96, 96)

            # 构建目标文件路径
            target_path = os.path.join(
                target_dir, 'OEBPS', 'Images', 'bg1.jpg')

            # 保存处理后的图片
            resized_img.save(target_path, 'JPEG', quality=95, dpi=(96, 96))
            return True
    except Exception as e:
        print(f"处理背景图片时出错：{str(e)}")


def update_copyright_info(target_dir, novel_name, author_name):
    """更新版权信息页面的书名和作者信息
    Args:
        target_dir: 目标目录路径
        novel_name: 小说名称
        author_name: 作者名称
    """
    copyright_path = os.path.join(target_dir, 'OEBPS', 'Text', 'copyright.xhtml')
    if os.path.exists(copyright_path):
        with open(copyright_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        # 处理每一行
        for i, line in enumerate(lines):
            if '书名' in line:
                lines[i] = line.replace('书名', novel_name)
            if '作者名' in line:
                lines[i] = line.replace('作者名', author_name)
            if '年月日' in line:
                current_time = time.strftime("%Y年%m月%d日")
                lines[i] = line.replace('年月日', current_time)

        # 写回文件
        with open(copyright_path, 'w', encoding='utf-8') as f:
            f.writelines(lines)
        print(f"已更新版权信息页面：{copyright_path}")
    else:
        print(f"错误：未找到文件 {copyright_path}")
        sys.exit(1)


def update_desc_info(target_dir, novel_name, desc):
    """更新内容简介页面的书名和简介信息
    Args:
        target_dir: 目标目录路径
        novel_name: 小说名称
        desc: 小说简介
    """
    desc_path = os.path.join(target_dir, 'OEBPS', 'Text', 'desc.xhtml')
    if os.path.exists(desc_path):
        with open(desc_path, 'r', encoding='utf-8') as f:
            content = f.read()

        # 替换书名
        content = content.replace('书名', novel_name)

        # 替换简介
        # 找到简介开始和结束的位置
        start_tag = '<div class="book-desc">'
        end_tag = '</div>'
        start_pos = content.find(start_tag)
        end_pos = content.find(end_tag, start_pos)

        if start_pos != -1 and end_pos != -1:
            # 保留标题部分
            title_end = content.find('</h1>', start_pos) + 5
            header = content[:title_end]
            footer = content[end_pos:]

            # 将简介文本按段落分割并格式化
            paragraphs = desc.split('\n')
            formatted_paragraphs = [
                f'    <p>{p.strip()}</p>' for p in paragraphs if p.strip()]
            new_content = header + '\n' + \
                '\n'.join(formatted_paragraphs) + '\n' + footer

            # 写回文件
            with open(desc_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
            print(f"已更新内容简介页面：{desc_path}")
        else:
            print(f"警告：未找到简介部分标记")
    else:
        print(f"错误：未找到文件 {desc_path}")


def update_font_files(target_dir, novel_name, author_name, toc_data, volume_prefaces, desc):
    try:
        # 收集需要添加到字体的文字
        title_chars = set(novel_name + author_name)  # 书名和作者名
        content_chars = set(desc)  # 简介文字

        # 添加卷前言中的文字
        for preface in volume_prefaces:
            content_chars.update(preface)

        # 从目录数据中收集文字
        for item in toc_data:
            title_chars.update(item['title'])
            if item['type'] == 'volume' and 'chapters' in item:
                for chapter in item['chapters']:
                    title_chars.update(chapter['title'])

        # 添加固定文字
        title_chars.update("0123456789第一二三四五六七八九十百千万部卷章节集简介")
        title_chars.update("版权信息")
        title_chars.update("作者名◎著")
        title_chars.update("[庄馆长]阡陌居论坛◎制")
        title_chars.update("制作时间：年月日")
        title_chars.update("版权声明：本书仅作个人排版参考学习之用，请勿用于商业用途。如果喜欢本书，请购买正版。任何对本书的修改、加工、传播，请自负法律后果。")
        # 合并内容
        title_chars.update(content_chars)

        # 模板字体文件路径
        template_dir = get_template_dir()
        template_kai_path = os.path.join(
            template_dir, 'OEBPS', 'Fonts', 'Kai.ttf')
        # 目标字体文件路径
        target_kai_path = os.path.join(
            target_dir, 'OEBPS', 'Fonts', 'Kai.ttf')
        # 确保目标目录存在
        os.makedirs(os.path.dirname(target_kai_path), exist_ok=True)

        # 更新内容字体（Kai.ttf）
        if os.path.exists(template_kai_path):
            # 复制模板字体文件
            shutil.copy2(template_kai_path, target_kai_path)
            font = TTFont(target_kai_path)
            # 创建子集
            options = Options()
            options.layout_features = ['*']
            subsetter = Subsetter(options=options)
            subsetter.populate(text=''.join(title_chars))
            subsetter.subset(font)
            font.save(target_kai_path)
            print(f"已更新字体：{target_kai_path}")
    except Exception as e:
        print(f"更新字体文件时出错：{str(e)}")
        # 不要直接退出，让程序继续运行
        return False

    return True


def create_epub(txt_file_path, novel_name, author_name, toc_data, volume_prefaces, cover_image_path=None, back_image_path=None, desc=None):
    """创建EPUB文件
    Args:
        txt_file_path: txt文件路径，用于确定目标目录
        novel_name: 小说名称
        author_name: 作者名称
        toc_data: 目录数据，包含卷和章节信息的列表
        volume_prefaces: 卷前言数据
        cover_image_path: 封面图片路径
        back_image_path: 背景图片路径
        desc: 小说简介
    Returns:
        bool: 是否成功创建
    """
    target_dir = None
    try:
        target_dir = copy_template(novel_name, txt_file_path)
        if not target_dir:
            return False

        # 如果提供了图片，处理并保存
        if cover_image_path:
            try:
                process_cover_image(novel_name, cover_image_path, target_dir)
            except Exception as e:
                print(f"处理封面图片时出错，将使用默认封面：{str(e)}")

        if back_image_path:
            try:
                process_back_image(back_image_path, target_dir)
            except Exception as e:
                print(f"处理背景图片时出错，将使用默认背景：{str(e)}")

        # 清空并复制XHTML文件
        text_dir = os.path.join(target_dir, 'OEBPS', 'Text')
        clear_text_directory(text_dir)

        # 复制XHTML文件
        try:
            copy_xhtml_files(target_dir, text_dir)
        except Exception as e:
            print(f"复制XHTML文件时出错：{str(e)}")
            return False

        # 更新content.opf和toc.ncx
        try:
            update_content_opf(target_dir, text_dir, novel_name)
            update_toc_ncx(target_dir, novel_name, toc_data)
        except Exception as e:
            print(f"更新目录文件时出错：{str(e)}")
            return False

        # 复制固定文件
        try:
            copy_fixed_files(text_dir)
        except Exception as e:
            print(f"复制固定文件时出错：{str(e)}")
            return False

        # 更新版权信息
        try:
            update_copyright_info(target_dir, novel_name, author_name)
        except Exception as e:
            print(f"更新版权信息时出错：{str(e)}")
            # 继续执行，非致命错误

        # 更新内容简介
        try:
            update_desc_info(target_dir, novel_name, desc)
        except Exception as e:
            print(f"更新内容简介时出错：{str(e)}")
            # 继续执行，非致命错误

        # 更新字体文件
        font_result = update_font_files(
            target_dir, novel_name, author_name, toc_data, volume_prefaces, desc)
        if not font_result:
            print("警告：字体文件更新失败，但将继续生成EPUB")

        print(f"EPUB目录更新完毕: {target_dir}")
        return True
    except Exception as e:
        print(f"错误：创建EPUB时出现问题：{str(e)}")
        # 如果出错且目标目录已创建，尝试清理
        if target_dir and os.path.exists(target_dir):
            try:
                shutil.rmtree(target_dir)
                print(f"已清理临时目录：{target_dir}")
            except:
                print(f"清理临时目录失败：{target_dir}")
        return False
